#include "uwidgetutils.h"
#include "qrencode/qrencode.h"

#include <QPainter>
#include <QPainterPath>
#include <QApplication>
#include <QScreen>
#include <QPalette>
#include <QFile>
#include <QSvgRenderer>
#include <QWidget>

QT_BEGIN_NAMESPACE
//extern Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter* p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
QT_END_NAMESPACE

UWidgetUtils::UWidgetUtils()
{
}

QIcon UWidgetUtils::getNumCircleIcon(int num, const QFont &font, int size)
{
    QPixmap output(QSize(size, size));
    output.fill(Qt::transparent);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setPen(Qt::NoPen);

    QPainterPath path;
    path.addEllipse(0, 0, size, size);
    painter.setClipPath(path);
    painter.fillPath(path, Qt::gray);
    painter.setFont(font);
    painter.setPen(Qt::white);
    painter.drawText(QRect(0, 0, size, size), Qt::TextSingleLine | Qt::AlignCenter, QString::number(num));
    return QIcon(output);
}

QIcon UWidgetUtils::getCircleCloseIcon(int size)
{
    QPixmap output(QSize(size, size));
    output.fill(Qt::transparent);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setPen(Qt::NoPen);

    QPainterPath path;
    QRect rect(0, 0, size, size);
    path.addEllipse(rect);
    painter.setClipPath(path);
    painter.fillPath(path, qApp->palette().color(QPalette::Base));
    painter.drawPixmap(rect.adjusted(6, 6, -6, -6), QPixmap(":/images/close.svg"));
    return QIcon(output);
}

QIcon UWidgetUtils::getPassWordIcon(const QPixmap &pixmap, int size)
{
    QPixmap output(QSize(size, size));
    output.fill(Qt::transparent);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setPen(Qt::NoPen);

    QPainterPath path;
    QRect rect(0, 0, size, size);
    path.addRoundedRect(rect, 8, 8);
    painter.setClipPath(path);
    painter.fillPath(path, qApp->palette().color(QPalette::Highlight));
    painter.drawPixmap(rect.adjusted(6, 6, -6, -6), pixmap);
    return QIcon(output);
}

QImage UWidgetUtils::dropShadow(const QPixmap &px, qreal radius, const QColor &color)
{
    if (px.isNull())
    {
        return QImage();
    }

    QSize size = px.size();

    QImage tmp(size + QSize(radius * 2, radius * 2), QImage::Format_ARGB32_Premultiplied);
    tmp.fill(0);
    QPainter tmpPainter(&tmp);
    tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
    tmpPainter.drawPixmap(QPoint(radius, radius), px);
    tmpPainter.end();

    // blur the alpha channel
    QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
    blurred.fill(0);
    QPainter blurPainter(&blurred);
    qt_blurImage(&blurPainter, tmp, radius, false, true);
    blurPainter.end();

    if (color == QColor(Qt::black))
    {
        return blurred;
    }

    tmp = blurred;

    // blacken the image...
    tmpPainter.begin(&tmp);
    tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
    tmpPainter.fillRect(tmp.rect(), color);
    tmpPainter.end();

    return tmp;
}

void UWidgetUtils::moveToCenter(QWidget* w)
{
    Q_ASSERT(w != nullptr);

    QRect parentRect = QApplication::primaryScreen()->availableGeometry();

    if (w->parentWidget())
    {
        parentRect = w->parentWidget()->geometry();
    }
    w->move(parentRect.center() - w->rect().center());
}

QIcon UWidgetUtils::getCircleIcon(const QPixmap &pixmap, int diameter)
{
    QPixmap output(QSize(diameter, diameter));
    output.fill(Qt::transparent);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setPen(Qt::NoPen);

    QPainterPath path;
    path.addEllipse(0, 0, diameter, diameter);
    painter.setClipPath(path);
    painter.drawPixmap(0, 0, diameter, diameter, pixmap);
    return QIcon(output);
}

QIcon UWidgetUtils::getCircleIcon(const QIcon &icon, int diameter)
{
    QPixmap pixmap = icon.pixmap(QSize(diameter, diameter));
    return getCircleIcon(pixmap, diameter);
}

QPainterPath UWidgetUtils::roundedPath(int radius, const QRect &rect, const RadiuPosition &position)
{
    QPainterPath canDrawingPathArea;
    switch (position)
    {
        case Normal:
        {
            canDrawingPathArea.addRect(rect);
            break;
        }
        case LeftTop:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setY(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            QRect rightRect = rect.adjusted(rect.width() / 2, 0, 0, -rect.height() / 2);
            QPainterPath rightPath;
            rightPath.addRect(rightRect);
            canDrawingPathArea = canDrawingPathArea.united(rightPath);
            break;
        }
        case RightTop:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setY(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            QRect leftRect = rect.adjusted(0, 0, -rect.width() / 2, -rect.height() / 2);
            QPainterPath leftPath;
            leftPath.addRect(leftRect);
            canDrawingPathArea = canDrawingPathArea.united(leftPath);
            break;
        }
        case LeftBottom:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setHeight(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            QRect rightRect = rect.adjusted(rect.width() / 2, rect.height() / 2, 0, 0);
            QPainterPath rightPath;
            rightPath.addRect(rightRect);
            canDrawingPathArea = canDrawingPathArea.united(rightPath);
            break;
        }
        case RightBottom:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setHeight(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            QRect leftRect = rect.adjusted(0, rect.height() / 2, -rect.width() / 2, 0);
            QPainterPath leftPath;
            leftPath.addRect(leftRect);
            canDrawingPathArea = canDrawingPathArea.united(leftPath);
            break;
        }
        case Top:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setY(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            break;
        }
        case Bottom:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setHeight(rect.height() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            break;
        }
        case Left:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setX(rect.width() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            break;
        }
        case Right:
        {
            QRect calRect = rect;
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            calRect.setWidth(rect.width() / 2);
            QPainterPath addPath;
            addPath.addRect(calRect);
            canDrawingPathArea = canDrawingPathArea.united(addPath);
            break;
        }
        case All:
        {
            canDrawingPathArea.addRoundedRect(rect, radius, radius);
            break;
        }
        default:
            break;
    }

    return canDrawingPathArea;
}

QPixmap UWidgetUtils::generateQRcode(const QString &text, const QSize &size)
{
    //将QString转化为const char * |2-QR码版本为2 | QR_ECLEVEL_Q 容错等级 |QR_MODE_8 八字节数据 |1-区分大小写
    QRcode* qrcode = QRcode_encodeString(text.toStdString().c_str(), 2, QR_ECLEVEL_Q, QR_MODE_8, 1);
    qint32 qrcode_width = qrcode->width > 0 ? qrcode->width : 1;
    double scale_x = (double)size.width() / (double)qrcode_width;
    double scale_y = (double)size.height() / (double)qrcode_width;

    QPixmap output(size);
    output.fill(Qt::white);
    QPainter painter(&output);
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::black);

    for (qint32 y = 0; y < qrcode_width; y ++)
    {
        for (qint32 x = 0; x < qrcode_width; x++)
        {
            unsigned char b = qrcode->data[y * qrcode_width + x];
            if (b & 0x01)
            {
                QRectF r(x * scale_x, y * scale_y, scale_x, scale_y);
                painter.drawRects(&r, 1);
            }
        }
    }

    QRcode_free(qrcode);
    return output;
}

QPixmap UWidgetUtils::generateQRcode(const QString &text, int scale)
{
    QRcode* qrcode = QRcode_encodeString(text.toStdString().c_str(), 2, QR_ECLEVEL_Q, QR_MODE_8, 1);
    qint32 qrcode_width = qrcode->width > 0 ? qrcode->width : 1;

    QPixmap output(qrcode_width * scale, qrcode_width * scale);
    output.fill(Qt::white);
    QPainter painter(&output);
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::black);

    for (qint32 y = 0; y < qrcode_width; y ++)
    {
        for (qint32 x = 0; x < qrcode_width; x++)
        {
            unsigned char b = qrcode->data[y * qrcode_width + x];
            if (b & 0x01)
            {
                QRectF r(x * scale, y * scale, scale, scale);
                painter.drawRects(&r, 1);
            }
        }
    }

    QRcode_free(qrcode);
    return output;
}

QPixmap UWidgetUtils::generateQRcode(const QPixmap &pixmap, const QString &text, const QSize &size)
{
    QPixmap output = generateQRcode(text, size);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    QRect rect = QRect((size.width() - pixmap.width()) / 2, (size.height() - pixmap.height()) / 2, pixmap.width(), pixmap.height());
    painter.drawPixmap(rect, pixmap);

    return output;
}

QPixmap UWidgetUtils::generateQRcode(const QString &iconPath, const QSize &iconSize, const QString &text, const QSize &size)
{
    QPixmap output = generateQRcode(text, size);
    QPainter painter(&output);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    QRect rect = QRect((iconSize.width() - iconSize.width()) / 2, (size.height() - iconSize.height()) / 2, iconSize.width(), iconSize.height());
    painter.drawPixmap(rect, QPixmap(iconPath));

    return output;
}

void UWidgetUtils::setSVGBackGroudColor(QDomElement &elem, const QString &tagname, const QString &attr, const QString &colorString)
{
    if (0 == elem.tagName().compare(tagname))
    {
        elem.setAttribute(attr, colorString);
    }
    for (int i = 0; i < elem.childNodes().count(); i++)
    {
        if (!elem.childNodes().at(i).isElement())
        {
            continue;
        }
        auto element = elem.childNodes().at(i).toElement();
        setSVGBackGroudColor(element, tagname, attr, colorString);
    }
}

QPixmap UWidgetUtils::generateSvgPixmap(const QString &fileName, const QSize &size, const QString &colorString)
{
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly))
    {
        return QPixmap();
    }
    QByteArray data = file.readAll();
    QDomDocument doc;
    doc.setContent(data);
    file.close();

    auto root = doc.documentElement();
    setSVGBackGroudColor(root, "path", "fill", colorString);

    QByteArray svg_content = doc.toByteArray();
    QSvgRenderer svg_render(svg_content);
    QPixmap pixmap(size);
    pixmap.fill(Qt::transparent);
    QPainter painter(&pixmap);
    svg_render.render(&painter);

    return pixmap;
}
